import tkinter as tk
from tkinter import ttk, messagebox, filedialog
from tkinterdnd2 import DND_FILES, TkinterDnD
import os
from PIL import Image, ImageTk
# pylint: disable=no-member
import cv2  # type: ignore[import]
from typing import Optional, Tuple, Any
import numpy as np

# Type aliases for cv2
CV2Capture = cv2.VideoCapture
CV2Frame = np.ndarray
import tempfile
import threading
from queue import Queue, Empty
import time
import logging
from config import ICON_PNG_PATH, ICON_ICO_PATH, ICON_SIZE
import ctypes
import sys

logger = logging.getLogger(__name__)

def set_app_id():
    """设置Windows应用程序ID"""
    if sys.platform == 'win32':
        try:
            # 设置应用程序ID
            myappid = "ai_video_txt.video_transcription.1.0"
            ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
        except Exception as e:
            logger.error(f"设置应用程序ID时出错: {str(e)}")

class VideoTranscriptionGUI:
    def __init__(self, app):
        # 设置Windows应用程序ID
        set_app_id()
        
        self.app = app
        self.root = TkinterDnD.Tk()
        self.root.title("视频转文字工具")
        self.root.geometry("800x660")
        
        # 设置应用图标
        try:
            if os.path.exists(ICON_ICO_PATH):
                # 优先使用ICO文件
                self.root.iconbitmap(default=ICON_ICO_PATH)
                # 为所有对话框设置相同的图标
                self.root.tk.call('wm', 'iconbitmap', self.root._w, ICON_ICO_PATH)
            elif os.path.exists(ICON_PNG_PATH):
                # 如果没有ICO文件，则使用PNG文件
                # 打开PNG图像
                image = Image.open(ICON_PNG_PATH)
                # 调整大小
                image = image.resize((ICON_SIZE, ICON_SIZE), Image.Resampling.LANCZOS)
                # 保存为临时ICO文件
                temp_ico = tempfile.NamedTemporaryFile(suffix='.ico', delete=False)
                image.save(temp_ico.name, format='ICO')
                # 设置图标
                self.root.iconbitmap(default=temp_ico.name)
                # 为所有对话框设置相同的图标
                self.root.tk.call('wm', 'iconbitmap', self.root._w, temp_ico.name)
                # 删除临时文件
                os.unlink(temp_ico.name)
            else:
                logger.warning(f"图标文件不存在: {ICON_PNG_PATH} 或 {ICON_ICO_PATH}")
        except Exception as e:
            logger.error(f"设置图标时出错: {str(e)}")
        
        # 创建消息队列用于线程间通信
        self.message_queue = Queue()
        
        # 存储当前视频路径
        self.current_video_path = None
        
        # 创建主框架
        self.main_frame = ttk.Frame(self.root, padding="10")
        self.main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 创建拖放区域
        self.drop_frame = ttk.LabelFrame(self.main_frame, text="拖放视频文件到这里", padding="20")
        self.drop_frame.grid(row=0, column=0, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=10)
        
        # 创建预览区域
        self.preview_frame = ttk.Frame(self.drop_frame)
        self.preview_frame.grid(row=0, column=0, pady=10)
        
        self.preview_label = ttk.Label(self.preview_frame, text="将视频文件拖放到这里")
        self.preview_label.grid(row=0, column=0)
        
        # 创建视频控制按钮区域
        self.video_control_frame = ttk.Frame(self.drop_frame)
        self.video_control_frame.grid(row=1, column=0, pady=5)
        
        self.clear_video_button = ttk.Button(self.video_control_frame, text="清除视频", command=self.clear_video)
        self.clear_video_button.grid(row=0, column=0, padx=5)
        self.clear_video_button.state(['disabled'])  # 初始状态为禁用
        
        self.start_process_button = ttk.Button(self.video_control_frame, text="开始处理", command=self.start_processing)
        self.start_process_button.grid(row=0, column=1, padx=5)
        self.start_process_button.state(['disabled'])  # 初始状态为禁用
        
        # 创建输出路径选择区域
        self.output_frame = ttk.LabelFrame(self.main_frame, text="输出设置", padding="10")
        self.output_frame.grid(row=2, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=10)
        
        self.output_path_var = tk.StringVar()
        self.output_entry = ttk.Entry(self.output_frame, textvariable=self.output_path_var, width=50)
        self.output_entry.grid(row=0, column=0, padx=5)
        
        self.output_button = ttk.Button(self.output_frame, text="选择输出路径", command=self.select_output_path)
        self.output_button.grid(row=0, column=1, padx=5)
        
        # 创建模型选择区域
        self.model_frame = ttk.LabelFrame(self.main_frame, text="AI模型配置", padding="10")
        self.model_frame.grid(row=3, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=10)
        
        # 创建场景选择区域
        self.scenario_frame = ttk.LabelFrame(self.main_frame, text="Temperature 设置", padding="10")
        self.scenario_frame.grid(row=4, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=10)
        
        # 场景选择变量
        self.scenario_var = tk.StringVar(value="1.0")
        
        # 创建场景选择单选按钮
        self.scenario_radio_frame = ttk.Frame(self.scenario_frame)
        self.scenario_radio_frame.grid(row=0, column=0, sticky=tk.W)
        
        # 添加场景选项
        scenarios = [
            ("代码生成/数学解题", "0.0"),
            ("数据抽取/分析", "1.0"), 
            ("通用对话/翻译", "1.3"),
            ("创意类写作/诗歌创作", "1.5")
        ]
        
        for i, (text, value) in enumerate(scenarios):
            radio = ttk.Radiobutton(
                self.scenario_radio_frame,
                text=text,
                variable=self.scenario_var,
                value=value,
                command=self.change_scenario
            )
            radio.grid(row=i//3, column=i%3, padx=10, pady=5, sticky=tk.W)
        
        # 模型选择 - 简化为只有两个选项的单选按钮
        self.model_var = tk.StringVar(value="deepseek-chat")
        ttk.Label(self.model_frame, text="选择模型:").grid(row=0, column=0, padx=5, sticky=tk.W)
        
        # 创建单选按钮组
        self.model_radio_frame = ttk.Frame(self.model_frame)
        self.model_radio_frame.grid(row=0, column=1, sticky=tk.W)
        
        # 添加模型选项单选按钮
        self.chat_radio = ttk.Radiobutton(
            self.model_radio_frame, 
            text="DeepSeek Chat (快速回答)", 
            variable=self.model_var, 
            value="deepseek-chat",
            command=self.change_model
        )
        self.chat_radio.grid(row=0, column=0, padx=10, sticky=tk.W)
        
        self.reasoner_radio = ttk.Radiobutton(
            self.model_radio_frame, 
            text="DeepSeek Reasoner (深度思考)", 
            variable=self.model_var, 
            value="deepseek-reasoner",
            command=self.change_model
        )
        self.reasoner_radio.grid(row=0, column=1, padx=10, sticky=tk.W)
        
        # 创建状态显示区域
        self.status_frame = ttk.LabelFrame(self.main_frame, text="处理状态", padding="10")
        self.status_frame.grid(row=5, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=10)
        
        # 状态标签
        self.status_label = ttk.Label(self.status_frame, text="就绪")
        self.status_label.grid(row=0, column=0, sticky=tk.W)
        
        # 进度条
        self.progress_var = tk.DoubleVar()
        self.progress_bar = ttk.Progressbar(
            self.status_frame,
            variable=self.progress_var,
            maximum=100,
            mode='determinate'
        )
        self.progress_bar.grid(row=0, column=1, sticky=(tk.W, tk.E), padx=5)
        self.progress_bar.grid_remove()  # 初始时隐藏进度条
        
        # 创建打开文件按钮
        self.open_file_button = ttk.Button(self.status_frame, text="打开生成的文件", command=self.open_output_file)
        self.open_file_button.grid(row=0, column=2, padx=5)
        self.open_file_button.state(['disabled'])  # 初始状态为禁用
        
        # 配置拖放
        self.drop_frame.drop_target_register(DND_FILES)
        self.drop_frame.dnd_bind('<<Drop>>', self.handle_drop)
        
        # 配置网格权重
        self.root.grid_rowconfigure(0, weight=1)
        self.root.grid_columnconfigure(0, weight=1)
        self.main_frame.grid_columnconfigure(0, weight=1)
        
        # 保存最后生成的文件路径
        self.last_output_file = None
        
        # 定期检查消息队列
        self.check_message_queue()
        
    def check_message_queue(self):
        """检查消息队列并处理消息"""
        try:
            while True:
                message = self.message_queue.get_nowait()
                if message['type'] == 'status':
                    self.status_label.config(text=message['text'])
                elif message['type'] == 'error':
                    messagebox.showerror("错误", message['text'])
                elif message['type'] == 'success':
                    messagebox.showinfo("成功", message['text'])
                    if 'auto_open' in message and message['auto_open']:
                        self.status_label.config(text="已打开生成的文件")
                        self.root.after(2000, lambda: self.status_label.config(text="就绪"))
                elif message['type'] == 'progress':
                    self.progress_var.set(message['value'])
                elif message['type'] == 'show_progress':
                    self.progress_bar.grid()
                    self.progress_var.set(0)
                elif message['type'] == 'hide_progress':
                    self.progress_bar.grid_remove()
                    self.progress_var.set(0)
        except Empty:
            pass
        finally:
            self.root.after(100, self.check_message_queue)
        
    def select_output_path(self):
        """选择输出路径"""
        file_path = filedialog.asksaveasfilename(
            defaultextension=".md",
            filetypes=[("Markdown files", "*.md"), ("All files", "*.*")],
            initialdir=os.path.dirname(self.output_path_var.get()) if self.output_path_var.get() else None
        )
        if file_path:
            if not file_path.endswith('.md'):
                file_path = os.path.splitext(file_path)[0] + '.md'
            self.output_path_var.set(file_path)
            
    def handle_drop(self, event: Any) -> None:
        """处理文件拖放
        Args:
            event: The drop event containing file path
        """
        file_path: str = event.data
        if file_path.startswith('{') and file_path.endswith('}'):
            file_path = file_path[1:-1]
        
        if not os.path.exists(file_path):
            messagebox.showerror("错误", "文件不存在")
            return
            
        # 如果没有设置输出路径，使用默认路径
        if not self.output_path_var.get():
            default_output = os.path.splitext(file_path)[0] + ".md"
            self.output_path_var.set(default_output)
            
        # 保存视频路径并启用按钮
        self.current_video_path = file_path
        self.clear_video_button.state(['!disabled'])
        self.start_process_button.state(['!disabled'])
        
        # 清除旧的预览
        self.preview_label.config(image="")
        if hasattr(self.preview_label, 'image'):
            self.preview_label.image = None
        self.preview_label.config(text="正在加载预览...")
        
        try:
            # 读取视频第一帧
            cap: CV2Capture = cv2.VideoCapture(file_path)  # type: ignore[attr-defined]
            if not cap.isOpened():
                raise Exception("无法打开视频文件")
            
            # 重置视频捕获对象的所有属性
            cap.set(cv2.CAP_PROP_POS_FRAMES, 0)  # type: ignore[attr-defined]
            cap.set(cv2.CAP_PROP_FRAME_WIDTH, 0)  # type: ignore[attr-defined]
            cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 0)  # type: ignore[attr-defined]
            cap.set(cv2.CAP_PROP_FPS, 0)  # type: ignore[attr-defined]
            
            # 读取第一帧
            ret: bool
            frame: CV2Frame
            ret, frame = cap.read()
            if not ret:
                raise Exception("无法读取视频帧")
            
            # 释放视频捕获对象
            cap.release()
            
            # 调整图片大小
            height: int
            width: int
            height, width = frame.shape[:2]
            max_size = 200
            if height > max_size or width > max_size:
                scale = max_size / max(height, width)
                new_width = int(width * scale)
                new_height = int(height * scale)
                frame = cv2.resize(frame, (new_width, new_height))
            
            # 转换颜色空间
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)  # type: ignore[attr-defined, no-member]
            
            # 转换为PIL图像
            image = Image.fromarray(frame)
            photo = ImageTk.PhotoImage(image=image)
            
            # 更新预览标签
            self.preview_label.config(image=photo)
            self.preview_label.image = photo
            
            # 显示成功提示
            self.message_queue.put({
                'type': 'status',
                'text': "视频加载成功！"
            })
            self.root.after(2000, lambda: self.message_queue.put({
                'type': 'status',
                'text': "就绪"
            }))
        except Exception as e:
            print(f"生成缩略图时出错: {str(e)}")
            self.preview_label.config(text="生成预览失败")
            self.message_queue.put({
                'type': 'error',
                'text': f"生成缩略图时出错: {str(e)}"
            })
        
    def process_video_thread(self, file_path: str) -> None:
        """在单独的线程中处理视频
        Args:
            file_path: Path to the video file
        """
        try:
            # 更新状态和显示进度条
            self.message_queue.put({
                'type': 'status',
                'text': "开始视频转写..."
            })
            self.message_queue.put({
                'type': 'show_progress'
            })
            
            # 获取视频总时长
            cap: CV2Capture = cv2.VideoCapture(file_path)  # type: ignore[attr-defined]
            total_duration: float = cap.get(cv2.CAP_PROP_FRAME_COUNT) / cap.get(cv2.CAP_PROP_FPS)  # type: ignore[attr-defined]
            cap.release()
            
            if total_duration <= 0:
                self.message_queue.put({
                    'type': 'error',
                    'text': "无法获取视频时长"
                })
                return
                
            # 处理视频
            def network_status_callback(status):
                """处理网络请求状态的回调函数"""
                self.message_queue.put({
                    'type': 'status',
                    'text': status
                })
                if "正在发送请求" in status:
                    # 在发送请求时显示进度条并设置为不确定模式
                    self.message_queue.put({
                        'type': 'show_progress'
                    })
                    self.root.after(0, lambda: self.progress_bar.config(mode='indeterminate'))
                    self.root.after(0, self.progress_bar.start)
                elif "收到响应" in status:
                    # 在收到响应时停止进度条动画并恢复确定模式
                    self.root.after(0, self.progress_bar.stop)
                    self.root.after(0, lambda: self.progress_bar.config(mode='determinate'))
            
            def progress_callback(progress):
                """处理进度更新的回调函数"""
                self.message_queue.put({
                    'type': 'progress',
                    'value': progress
                })
                # 更新状态文本
                self.message_queue.put({
                    'type': 'status',
                    'text': f"视频转写进度: {progress:.1f}%"
                })
            
            output_path = self.app.process_video(
                file_path,
                self.output_path_var.get(),
                progress_callback=lambda p: self.message_queue.put({'type': 'progress', 'value': p}),
                status_callback=lambda status: self.message_queue.put({'type': 'status', 'text': status})
            )
            
            if output_path:
                self.last_output_file = output_path
                self.open_file_button.state(['!disabled'])
                # 自动打开生成的文件
                if self.app.open_output_file(output_path):
                    self.message_queue.put({
                        'type': 'success',
                        'text': f"处理完成！\n输出文件：{output_path}",
                        'file_path': output_path,
                        'auto_open': True
                    })
                else:
                    self.message_queue.put({
                        'type': 'success',
                        'text': f"处理完成！\n输出文件：{output_path}\n但无法自动打开文件，请手动打开。",
                        'file_path': output_path
                    })
            else:
                self.message_queue.put({
                    'type': 'error',
                    'text': "处理失败"
                })
        except Exception as e:
            self.message_queue.put({
                'type': 'error',
                'text': f"处理出错：{str(e)}"
            })
        finally:
            self.message_queue.put({
                'type': 'status',
                'text': "就绪"
            })
            self.message_queue.put({
                'type': 'hide_progress'
            })
            
    def open_output_file(self):
        """打开生成的文件"""
        if self.last_output_file and os.path.exists(self.last_output_file):
            if self.app.open_output_file(self.last_output_file):
                self.status_label.config(text="已打开生成的文件")
                self.root.after(2000, lambda: self.status_label.config(text="就绪"))
            else:
                messagebox.showerror("错误", "无法打开文件")
        else:
            messagebox.showerror("错误", "没有可打开的文件")
            
    def change_scenario(self):
        """切换场景并自动配置合适的温度"""
        scenario = self.scenario_var.get()
        self.message_queue.put({
            'type': 'status',
            'text': f"正在切换到 {scenario} 场景..."
        })
        
        try:
            if not self.app.llm_interface.set_temperature(scenario):
                self.message_queue.put({
                    'type': 'status',
                    'text': "场景切换失败"
                })
                self.root.after(2000, lambda: self.message_queue.put({
                    'type': 'status',
                    'text': "就绪"
                }))
                return False
                
            self.message_queue.put({
                'type': 'status',
                'text': f"已切换到 {scenario} 场景"
            })
            self.root.after(2000, lambda: self.message_queue.put({
                'type': 'status',
                'text': "就绪"
            }))
            return True
        except Exception as e:
            self.message_queue.put({
                'type': 'status',
                'text': f"场景切换出错: {str(e)}"
            })
            self.root.after(2000, lambda: self.message_queue.put({
                'type': 'status',
                'text': "就绪"
            }))
            return False
            
    def change_model(self):
        """切换AI模型并自动配置合适的默认参数"""
        model_name = self.model_var.get()
        self.message_queue.put({
            'type': 'status',
            'text': f"正在切换到 {model_name}..."
        })
        
        try:
            # 切换模型
            if not self.app.change_llm_model(model_name):
                # 静默错误，仅在状态栏显示
                self.message_queue.put({
                    'type': 'status',
                    'text': "模型切换失败"
                })
                # 2秒后恢复状态
                self.root.after(2000, lambda: self.message_queue.put({
                    'type': 'status',
                    'text': "就绪"
                }))
                return False
                
            # 根据选择的模型自动配置合适的参数
            if model_name == "deepseek-reasoner":
                # 推理模型自动配置
                self.app.llm_interface.set_thinking_depth("reasoning")
                self.app.llm_interface.set_reasoning_steps(7)
                self.app.llm_interface.set_enable_cot(True)
                model_desc = "深度思考模式"
            else:
                # 聊天模型自动配置
                self.app.llm_interface.set_thinking_depth("balanced")
                self.app.llm_interface.set_reasoning_steps(5)
                self.app.llm_interface.set_enable_cot(False)
                model_desc = "快速回答模式"
            
            # 更新状态栏
            self.message_queue.put({
                'type': 'status',
                'text': f"已切换到{model_desc}"
            })
            # 2秒后恢复状态
            self.root.after(2000, lambda: self.message_queue.put({
                'type': 'status',
                'text': "就绪"
            }))
            return True
        except Exception as e:
            # 只在状态栏显示错误
            self.message_queue.put({
                'type': 'status',
                'text': f"模型切换出错: {str(e)}"
            })
            # 2秒后恢复状态
            self.root.after(2000, lambda: self.message_queue.put({
                'type': 'status',
                'text': "就绪"
            }))
            return False
            
    def clear_video(self):
        """清除已加载的视频"""
        self.current_video_path = None
        # 清除预览图片
        self.preview_label.config(image="")  # 先清除图片
        if hasattr(self.preview_label, 'image'):
            self.preview_label.image = None
        self.preview_label.config(text="将视频文件拖放到这里")  # 再设置文本
        self.clear_video_button.state(['disabled'])
        self.start_process_button.state(['disabled'])
        self.message_queue.put({
            'type': 'status',
            'text': "已清除视频"
        })
        self.root.after(2000, lambda: self.message_queue.put({
            'type': 'status',
            'text': "就绪"
        }))

    def start_processing(self):
        """开始处理视频"""
        if not self.current_video_path:
            messagebox.showerror("错误", "请先拖入视频文件")
            return
            
        if not self.output_path_var.get():
            messagebox.showerror("错误", "请选择输出路径")
            return
            
        # 创建进度处理线程
        self.message_queue.put({'type': 'show_progress'})
        
        # 在工作线程中执行耗时操作
        thread = threading.Thread(target=self.process_video_thread, args=(self.current_video_path,))
        thread.daemon = True
        thread.start()
            
    def run(self):
        """运行GUI程序"""
        self.root.mainloop()
